`timescale 1ns/1ns

// 仅为演示采样时机, 仿真器行为天差地别, 切勿用到项目中 !!!

module coverage_sampling_timing_1;

    bit clk;   // 时钟信号
    
    int data1; // 用于时钟事件采样
    int data2; // 用于方法调用采样

    // 辅助函数, 用于在采样时打印哪个 covergroup 在何时采样了哪个值, 并总是返回 1, 以确保采样继续进行
    function automatic bit print_and_sample(string cg_name, string cp_name, int val);
        $display("@%0t\t[COVERAGE IFF] - %s Sampling '%s' with value: %0d", $time, cg_name, cp_name, val);
        return 1; // 必须返回 1, 否则采样会被阻止
    endfunction

    // 覆盖组 时钟事件采样
    // 在时钟上升沿的瞬间采样, 此时 data1 的值还未更新
    covergroup cg_clock_event @(posedge clk);
        option.per_instance = 1;
        cp_data1: coverpoint data1 iff (print_and_sample("cg_clock_event", "data1", data1));
    endgroup

    // 覆盖组  strobe 时钟事件采样
    // 在时钟事件所在时间槽的 Postponed 区域采样, 此时 data1 的值已经更新
    covergroup cg_strobe_event @(posedge clk);
        option.per_instance = 1;
        type_option.strobe = 1; // 关键选项：启用strobe采样
        cp_data1: coverpoint data1 iff (print_and_sample("cg_strobe_event", "data1", data1));
    endgroup

    // 覆盖组 方法调用采样
    // 显式采样
    covergroup cg_sample_method;
        option.per_instance = 1;
        cp_data2: coverpoint data2 iff (print_and_sample("cg_sample_method", "data2", data2));
    endgroup

    // 实例化 covergroup
    cg_clock_event    cg_inst1 = new;
    cg_sample_method  cg_inst2 = new;
    cg_strobe_event   cg_inst3 = new;

    // 时钟生成
    initial begin
        clk = 0;
        forever #5 clk = ~clk;
    end

    initial begin
        data1 = 0;
        data2 = 0;

        $display("@%0t\t[TestStart] data1=%0d, data2=%0d", $time, data1, data2);

        @(posedge clk);
        data1 = 1234;
        $display("@%0t\t@(posedge clk), data1 <- 1234", $time);

        #1;
        data2 = 5678;
        $display("@%0t\t#1 data2 <- 5678, call sample()", $time);
        cg_inst2.sample();

        @(posedge clk);
        $display("@%0t\t@(posedge clk), data1 is 1234", $time);

        #1;
        data1 = 2468;
        $display("@%0t\tdata1 <- 2468", $time);

        #20;
        $display("@%0t\t[TestEnd]", $time);
        $finish;
    end

endmodule

/* Output: VCS
@0      [TestStart] data1=0, data2=0
@5      [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 0
@5      [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 0
@5      @(posedge clk), data1 <- 1234
@6      #1 data2 <- 5678, call sample()
@6      [COVERAGE IFF] - cg_sample_method Sampling 'data2' with value: 5678
@15     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 1234
@15     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 1234
@15     @(posedge clk), data1 is 1234
@16     data1 <- 2468
@25     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
@25     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
@35     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
@35     [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
@36     [TestEnd]
*/
/* Output: QuestaSim
# @0    [TestStart] data1=0, data2=0
# @5    [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 0
# @5    [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 0
# @5    @(posedge clk), data1 <- 1234
# @5    [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 1234
# @5    [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 1234
# @6    #1 data2 <- 5678, call sample()
# @6    [COVERAGE IFF] - cg_sample_method Sampling 'data2' with value: 5678
# @6    [COVERAGE IFF] - cg_sample_method Sampling 'data2' with value: 5678
# @15   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 1234
# @15   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 1234
# @15   @(posedge clk), data1 is 1234
# @15   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 1234
# @15   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 1234
# @16   data1 <- 2468
# @25   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
# @25   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
# @25   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 2468
# @25   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 2468
# @35   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
# @35   [COVERAGE IFF] - cg_clock_event Sampling 'data1' with value: 2468
# @35   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 2468
# @35   [COVERAGE IFF] - cg_strobe_event Sampling 'data1' with value: 2468
# @36   [TestEnd]
*/